<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>局域网文件传输</title>
    <script src="https://cdn.tailwindcss.com"></script>
    <script src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js" defer></script>
    <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
</head>
<body class="bg-gray-100 min-h-screen">
    <div x-data="app()" x-init="init()" class="container mx-auto px-4 py-8 max-w-6xl">
        <!-- 密码输入页面 -->
        <div x-show="!authenticated" class="max-w-md mx-auto mt-20">
            <div class="bg-white rounded-lg shadow-lg p-8">
                <h1 class="text-3xl font-bold text-center mb-8 text-gray-800">局域网文件传输</h1>

                <div class="mb-6">
                    <label class="block text-gray-700 text-sm font-bold mb-2">
                        请输入6位数字密码
                    </label>
                    <input
                        type="password"
                        x-model="password"
                        @keyup.enter="authenticate"
                        class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
                        placeholder="请输入密码"
                        maxlength="6"
                    >
                </div>

                <div x-show="errorMessage" class="mb-4 p-3 bg-red-100 border border-red-400 text-red-700 rounded">
                    <span x-text="errorMessage"></span>
                </div>

                <button
                    @click="authenticate"
                    :disabled="loading"
                    class="w-full bg-blue-500 hover:bg-blue-600 text-white font-bold py-3 px-4 rounded-lg transition duration-200"
                    :class="{ 'opacity-50 cursor-not-allowed': loading }"
                >
                    <span x-show="!loading">访问</span>
                    <span x-show="loading">验证中...</span>
                </button>
            </div>
        </div>

        <!-- 文件列表页面 -->
        <div x-show="authenticated">
            <div class="bg-white rounded-lg shadow-lg p-6 mb-6">
                <div class="flex justify-between items-center mb-6">
                    <h1 class="text-3xl font-bold text-gray-800">可下载文件</h1>
                    <div class="text-sm text-gray-600">
                        <span>共 <span x-text="files.length"></span> 个文件</span>
                        <span class="ml-4">总大小: <span x-text="totalSize"></span></span>
                    </div>
                </div>

                <!-- 操作按钮 -->
                <div class="flex gap-4 mb-6 flex-wrap">
                    <button
                        @click="selectAll"
                        class="px-4 py-2 bg-gray-500 hover:bg-gray-600 text-white rounded-lg transition duration-200"
                    >
                        全选
                    </button>
                    <button
                        @click="selectNone"
                        class="px-4 py-2 bg-gray-500 hover:bg-gray-600 text-white rounded-lg transition duration-200"
                    >
                        取消全选
                    </button>
                    <button
                        @click="downloadSelected"
                        :disabled="selectedFiles.length === 0"
                        class="px-4 py-2 bg-green-500 hover:bg-green-600 text-white rounded-lg transition duration-200"
                        :class="{ 'opacity-50 cursor-not-allowed': selectedFiles.length === 0 }"
                    >
                        下载所选 (<span x-text="selectedFiles.length"></span>)
                    </button>
                    <button
                        @click="refreshFiles"
                        class="px-4 py-2 bg-blue-500 hover:bg-blue-600 text-white rounded-lg transition duration-200"
                    >
                        刷新列表
                    </button>
                    <button
                        @click="showFilterRules = true"
                        class="px-4 py-2 bg-purple-500 hover:bg-purple-600 text-white rounded-lg transition duration-200"
                    >
                        📋 文件过滤规则
                    </button>
                </div>

                <!-- 文件列表 -->
                <div class="space-y-3">
                    <template x-for="file in files" :key="file.id">
                        <div class="border border-gray-200 rounded-lg p-4 hover:bg-gray-50 transition duration-150">
                            <div class="flex items-center">
                                <!-- 复选框 -->
                                <input
                                    type="checkbox"
                                    :value="file.id"
                                    x-model="selectedFiles"
                                    class="w-5 h-5 text-blue-500 rounded mr-4"
                                >

                                <!-- 文件信息 -->
                                <div class="flex-1 flex items-center justify-between">
                                    <div class="flex-1">
                                        <h3 class="font-semibold text-gray-800" x-text="file.name"></h3>
                                        <div class="text-sm text-gray-600 mt-1">
                                            <span x-text="formatSize(file.size)"></span>
                                            <span class="mx-2">•</span>
                                            <span x-text="file.type === 'directory' ? '文件夹' : '文件'"></span>
                                        </div>
                                    </div>

                                    <!-- 三个点菜单 -->
                                    <div class="relative ml-4" x-data="{ open: false }">
                                        <button
                                            @click="open = !open"
                                            @click.away="open = false"
                                            class="p-2 hover:bg-gray-200 rounded-full transition duration-200"
                                        >
                                            <svg class="w-6 h-6 text-gray-600" fill="currentColor" viewBox="0 0 24 24">
                                                <circle cx="12" cy="5" r="2"/>
                                                <circle cx="12" cy="12" r="2"/>
                                                <circle cx="12" cy="19" r="2"/>
                                            </svg>
                                        </button>

                                        <!-- 下拉菜单 -->
                                        <div
                                            x-show="open"
                                            x-transition
                                            class="absolute right-0 mt-2 w-48 bg-white rounded-lg shadow-lg border border-gray-200 z-10"
                                        >
                                            <button
                                                @click="downloadFile(file); open = false"
                                                class="w-full text-left px-4 py-3 hover:bg-gray-100 transition duration-150 rounded-t-lg flex items-center gap-2"
                                            >
                                                <svg class="w-5 h-5 text-blue-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                                                    <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4"></path>
                                                </svg>
                                                <span>下载</span>
                                            </button>
                                            <button
                                                x-show="file.type === 'directory'"
                                                @click="showDetails(file); open = false"
                                                class="w-full text-left px-4 py-3 hover:bg-gray-100 transition duration-150 rounded-b-lg flex items-center gap-2"
                                            >
                                                <svg class="w-5 h-5 text-green-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                                                    <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
                                                </svg>
                                                <span>详情</span>
                                            </button>
                                        </div>
                                    </div>
                                </div>
                            </div>
                        </div>
                    </template>

                    <!-- 空状态 -->
                    <div x-show="files.length === 0" class="text-center py-12 text-gray-500">
                        <svg class="mx-auto h-12 w-12 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                            <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 21h10a2 2 0 002-2V9.414a1 1 0 00-.293-.707l-5.414-5.414A1 1 0 0012.586 3H7a2 2 0 00-2 2v14a2 2 0 002 2z"></path>
                        </svg>
                        <p class="mt-4 text-lg">暂无可下载文件</p>
                    </div>
                </div>
            </div>
        </div>

        <!-- 文件夹详情弹窗(树形结构) -->
        <div
            x-show="detailsOpen"
            x-transition
            class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50"
            @click.self="detailsOpen = false"
        >
            <div class="bg-white rounded-lg shadow-xl max-w-4xl w-full mx-4 max-h-[85vh] flex flex-col">
                <!-- 弹窗头部 -->
                <div class="flex justify-between items-center p-6 border-b">
                    <div>
                        <h2 class="text-2xl font-bold text-gray-800" x-text="selectedFolder ? selectedFolder.name : ''"></h2>
                        <p class="text-sm text-gray-600 mt-1">
                            <span x-text="selectedFolder && selectedFolder.children ? selectedFolder.children.length : 0"></span> 个文件
                            <span class="mx-2">•</span>
                            <span x-text="selectedFolder ? formatSize(selectedFolder.size) : ''"></span>
                        </p>
                    </div>
                    <button
                        @click="detailsOpen = false"
                        class="text-gray-400 hover:text-gray-600 transition"
                    >
                        <svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                            <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path>
                        </svg>
                    </button>
                </div>

                <!-- 树形文件列表 -->
                <div class="p-6 overflow-y-auto flex-1">
                    <div x-show="flattenedTree && flattenedTree.length > 0" class="space-y-1">
                        <template x-for="item in flattenedTree" :key="item.id">
                            <div>
                                <div :style="`padding-left: ${item.level * 24 + 12}px`"
                                     class="flex items-center py-2 px-3 hover:bg-gray-50 rounded transition cursor-pointer"
                                     @click="item.hasChildren ? toggleNode(item.id) : null">
                                    <!-- 展开/收起按钮区域 -->
                                    <span class="w-5 h-5 flex items-center justify-center mr-2 text-gray-600">
                                        <template x-if="item.hasChildren">
                                            <svg class="w-4 h-4 transition-transform duration-200"
                                                 :class="{ 'rotate-90': item.expanded }"
                                                 fill="currentColor" viewBox="0 0 20 20">
                                                <path fill-rule="evenodd" d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z" clip-rule="evenodd"></path>
                                            </svg>
                                        </template>
                                    </span>

                                    <!-- 文件夹/文件图标 -->
                                    <template x-if="item.isDirectory">
                                        <svg class="w-5 h-5 text-yellow-500 mr-2 flex-shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                                            <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 7v10a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-6l-2-2H5a2 2 0 00-2 2z"></path>
                                        </svg>
                                    </template>
                                    <template x-if="!item.isDirectory">
                                        <svg class="w-5 h-5 text-blue-500 mr-2 flex-shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                                            <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 21h10a2 2 0 002-2V9.414a1 1 0 00-.293-.707l-5.414-5.414A1 1 0 0012.586 3H7a2 2 0 00-2 2v14a2 2 0 002 2z"></path>
                                        </svg>
                                    </template>

                                    <!-- 名称和大小 -->
                                    <div class="flex-1 min-w-0">
                                        <span class="font-medium text-gray-800" x-text="item.name"></span>
                                        <template x-if="item.size > 0">
                                            <span class="text-sm text-gray-500 ml-2" x-text="formatSize(item.size)"></span>
                                        </template>
                                    </div>
                                </div>
                            </div>
                        </template>
                    </div>

                    <!-- 空状态 -->
                    <div x-show="!selectedFolder || !selectedFolder.children || selectedFolder.children.length === 0" class="text-center py-8 text-gray-500">
                        <p>该文件夹为空</p>
                    </div>
                </div>

                <!-- 弹窗底部 -->
                <div class="p-6 border-t">
                    <button
                        @click="detailsOpen = false"
                        class="w-full px-4 py-2 bg-gray-500 hover:bg-gray-600 text-white rounded-lg transition duration-200"
                    >
                        关闭
                    </button>
                </div>
            </div>
        </div>

        <!-- 文件过滤规则弹窗 -->
        <div
            x-show="showFilterRules"
            x-transition
            class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50"
            @click.self="showFilterRules = false"
        >
            <div class="bg-white rounded-lg shadow-xl max-w-4xl w-full mx-4 max-h-[85vh] flex flex-col">
                <!-- 弹窗头部 -->
                <div class="flex justify-between items-center p-6 border-b">
                    <div>
                        <h2 class="text-2xl font-bold text-gray-800">文件过滤规则</h2>
                        <p class="text-sm text-gray-600 mt-1">以下文件和目录在添加文件夹时会被自动忽略</p>
                    </div>
                    <button
                        @click="showFilterRules = false"
                        class="text-gray-400 hover:text-gray-600 transition"
                    >
                        <svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                            <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path>
                        </svg>
                    </button>
                </div>

                <!-- 规则内容 -->
                <div class="p-6 overflow-y-auto flex-1">
                    <div class="grid grid-cols-1 md:grid-cols-2 gap-6">
                        <!-- 排除的目录 -->
                        <div>
                            <h3 class="text-lg font-semibold text-gray-800 mb-3 flex items-center">
                                <svg class="w-5 h-5 text-yellow-500 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                                    <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 7v10a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-6l-2-2H5a2 2 0 00-2 2z"></path>
                                </svg>
                                排除的目录
                            </h3>
                            <div class="space-y-2 bg-gray-50 p-4 rounded-lg max-h-96 overflow-y-auto">
                                <template x-for="dir in filterRules.excludeDirs" :key="dir">
                                    <div class="flex items-center text-sm text-gray-700 bg-white px-3 py-2 rounded border border-gray-200">
                                        <code class="font-mono" x-text="dir"></code>
                                    </div>
                                </template>
                            </div>
                        </div>

                        <!-- 排除的文件 -->
                        <div>
                            <h3 class="text-lg font-semibold text-gray-800 mb-3 flex items-center">
                                <svg class="w-5 h-5 text-blue-500 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                                    <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 21h10a2 2 0 002-2V9.414a1 1 0 00-.293-.707l-5.414-5.414A1 1 0 0012.586 3H7a2 2 0 00-2 2v14a2 2 0 002 2z"></path>
                                </svg>
                                排除的文件
                            </h3>
                            <div class="space-y-2 bg-gray-50 p-4 rounded-lg max-h-96 overflow-y-auto">
                                <template x-for="file in filterRules.excludeFiles" :key="file">
                                    <div class="flex items-center text-sm text-gray-700 bg-white px-3 py-2 rounded border border-gray-200">
                                        <code class="font-mono" x-text="file"></code>
                                    </div>
                                </template>
                            </div>
                        </div>

                        <!-- 排除的前缀 -->
                        <div>
                            <h3 class="text-lg font-semibold text-gray-800 mb-3 flex items-center">
                                <svg class="w-5 h-5 text-green-500 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                                    <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
                                </svg>
                                排除的前缀
                            </h3>
                            <div class="space-y-2 bg-gray-50 p-4 rounded-lg">
                                <template x-for="prefix in filterRules.excludePrefixes" :key="prefix">
                                    <div class="flex items-center text-sm text-gray-700 bg-white px-3 py-2 rounded border border-gray-200">
                                        <code class="font-mono" x-text="prefix === '.' ? '.(隐藏文件)' : prefix"></code>
                                    </div>
                                </template>
                            </div>
                        </div>

                        <!-- 说明 -->
                        <div class="md:col-span-1">
                            <h3 class="text-lg font-semibold text-gray-800 mb-3 flex items-center">
                                <svg class="w-5 h-5 text-orange-500 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                                    <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"></path>
                                </svg>
                                说明
                            </h3>
                            <div class="bg-blue-50 p-4 rounded-lg text-sm text-gray-700 space-y-2">
                                <p>• 以上规则在<strong>添加文件夹</strong>和<strong>下载文件夹</strong>时自动生效</p>
                                <p>• <code>*</code> 表示通配符，如 <code>*.log</code> 会排除所有日志文件</p>
                                <p>• 隐藏文件（以 <code>.</code> 开头）会被自动排除</p>
                                <p>• 这些规则有助于减小传输文件的大小</p>
                            </div>
                        </div>
                    </div>
                </div>

                <!-- 弹窗底部 -->
                <div class="p-6 border-t">
                    <button
                        @click="showFilterRules = false"
                        class="w-full px-4 py-2 bg-gray-500 hover:bg-gray-600 text-white rounded-lg transition duration-200"
                    >
                        关闭
                    </button>
                </div>
            </div>
        </div>
    </div>

    <script>
        function app() {
            return {
                authenticated: false,
                password: '',
                token: '',
                errorMessage: '',
                loading: false,
                files: [],
                selectedFiles: [],
                detailsOpen: false,
                selectedFolder: null,
                expandedNodes: {}, // 存储展开状态
                showFilterRules: false, // 过滤规则弹窗状态

                init() {
                    const savedToken = localStorage.getItem('token');
                    if (savedToken) {
                        this.token = savedToken;
                        this.loadFiles();
                    }
                },

                async authenticate() {
                    if (!this.password || this.password.length !== 6) {
                        this.errorMessage = '请输入6位数字密码';
                        return;
                    }

                    this.loading = true;
                    this.errorMessage = '';

                    try {
                        const response = await axios.post('/api/auth', {
                            password: this.password
                        });

                        if (response.data.success) {
                            this.token = response.data.data.token;
                            localStorage.setItem('token', this.token);
                            this.authenticated = true;
                            this.loadFiles();
                        } else {
                            this.errorMessage = response.data.message;
                        }
                    } catch (error) {
                        if (error.response) {
                            this.errorMessage = error.response.data.message || '认证失败';
                        } else {
                            this.errorMessage = '网络错误,请检查连接';
                        }
                    } finally {
                        this.loading = false;
                    }
                },

                async loadFiles() {
                    try {
                        const response = await axios.get('/api/files', {
                            headers: {
                                'Authorization': `Bearer ${this.token}`
                            }
                        });

                        if (response.data.success) {
                            this.files = response.data.data || [];
                            this.authenticated = true;
                        }
                    } catch (error) {
                        if (error.response && error.response.status === 401) {
                            localStorage.removeItem('token');
                            this.authenticated = false;
                            this.token = '';
                        }
                    }
                },

                async refreshFiles() {
                    await this.loadFiles();
                },

                selectAll() {
                    this.selectedFiles = this.files.map(f => f.id);
                },

                selectNone() {
                    this.selectedFiles = [];
                },

                downloadFile(file) {
                    const url = `/api/download/${file.id}?token=${this.token}`;
                    // 使用 a 标签下载
                    const a = document.createElement('a');
                    a.href = url;
                    a.download = file.name;
                    a.style.display = 'none';
                    document.body.appendChild(a);
                    a.click();
                    document.body.removeChild(a);
                },

                downloadSelected() {
                    if (this.selectedFiles.length === 0) {
                        return;
                    }

                    this.selectedFiles.forEach((fileId, index) => {
                        const file = this.files.find(f => f.id === fileId);
                        if (file) {
                            setTimeout(() => {
                                this.downloadFile(file);
                            }, index * 500);
                        }
                    });
                },

                showDetails(folder) {
                    this.selectedFolder = folder;
                    this.expandedNodes = {}; // 重置展开状态
                    this.detailsOpen = true;
                },

                toggleNode(nodeId) {
                    // 使用Alpine.js的响应式赋值方式
                    if (this.expandedNodes[nodeId]) {
                        delete this.expandedNodes[nodeId];
                    } else {
                        this.expandedNodes[nodeId] = true;
                    }
                    // 强制触发响应式更新
                    this.expandedNodes = { ...this.expandedNodes };
                },

                get flattenedTree() {
                    if (!this.selectedFolder || !this.selectedFolder.children) {
                        return [];
                    }

                    // 构建树形结构
                    const tree = this.buildTree(this.selectedFolder.children);

                    // 扁平化树形结构用于渲染
                    const result = [];
                    this.flattenTree(tree, result, 0, '');
                    return result;
                },

                // 根据路径构建树形结构
                buildTree(children) {
                    const tree = {};

                    children.forEach(item => {
                        // item.name 是相对路径，如 "folder1/file.txt" 或 "file.txt"
                        const parts = item.name.split('/').filter(p => p);
                        this.insertIntoTree(tree, parts, item);
                    });

                    return tree;
                },

                // 将项目插入树中
                insertIntoTree(tree, parts, item) {
                    if (parts.length === 0) return;

                    const currentPart = parts[0];
                    const isLastPart = parts.length === 1;

                    if (!tree[currentPart]) {
                        tree[currentPart] = {
                            name: currentPart,
                            isDirectory: !isLastPart || item.type === 'directory',
                            size: 0,
                            children: {}
                        };
                    }

                    if (isLastPart) {
                        // 叶子节点
                        if (item.type === 'file') {
                            tree[currentPart].size = item.size;
                        } else if (item.type === 'directory') {
                            // 如果是文件夹,使用后端返回的size
                            tree[currentPart].size = item.size || 0;
                        }
                    } else {
                        // 继续递归
                        this.insertIntoTree(tree[currentPart].children, parts.slice(1), item);
                        // 累加子项的大小到当前文件夹
                        if (item.type === 'file') {
                            tree[currentPart].size += item.size;
                        }
                    }
                },

                // 扁平化树形结构
                flattenTree(tree, result, level, parentPath) {
                    // 将对象转为数组并排序：文件夹在前，文件在后
                    const entries = Object.entries(tree).sort(([nameA, nodeA], [nameB, nodeB]) => {
                        if (nodeA.isDirectory && !nodeB.isDirectory) return -1;
                        if (!nodeA.isDirectory && nodeB.isDirectory) return 1;
                        return nameA.localeCompare(nameB);
                    });

                    entries.forEach(([name, node]) => {
                        const nodePath = parentPath ? `${parentPath}/${name}` : name;
                        const hasChildren = node.isDirectory && Object.keys(node.children).length > 0;
                        const expanded = this.expandedNodes[nodePath] || false;

                        result.push({
                            id: nodePath,
                            name: name,
                            level: level,
                            isDirectory: node.isDirectory,
                            hasChildren: hasChildren,
                            expanded: expanded,
                            size: node.size
                        });

                        // 如果是文件夹且已展开，递归添加子节点
                        if (node.isDirectory && expanded && hasChildren) {
                            this.flattenTree(node.children, result, level + 1, nodePath);
                        }
                    });
                },

                formatSize(bytes) {
                    if (bytes === 0) return '0 B';
                    const k = 1024;
                    const sizes = ['B', 'KB', 'MB', 'GB', 'TB'];
                    const i = Math.floor(Math.log(bytes) / Math.log(k));
                    return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
                },

                get totalSize() {
                    const total = this.files.reduce((sum, file) => sum + file.size, 0);
                    return this.formatSize(total);
                },

                // 过滤规则数据（写死在前端）
                get filterRules() {
                    return {
                        excludeDirs: [
                            // Python
                            '.venv', 'venv', 'env', '__pycache__', '.pytest_cache',
                            '.mypy_cache', '.tox', 'site-packages', '.eggs', '*.egg-info',

                            // Node.js
                            'node_modules', '.npm', '.yarn', '.pnp', 'bower_components',

                            // 编译输出
                            'build', 'dist', 'out', 'target', 'bin',

                            // IDE和编辑器
                            '.idea', '.vscode', '.vs', '.atom', '.sublime',

                            // 版本控制
                            '.git', '.svn', '.hg', '.bzr',

                            // 其他
                            '.cache', '.temp', '.tmp', 'tmp', 'temp', 'logs', '.log',

                            // macOS
                            '.Trash',

                            // Windows
                            '$RECYCLE.BIN',

                            // 特定工具
                            '.claude', '.codebuddy', '.playwright-mcp', '.specify',
                            '.next', '.nuxt', '.docusaurus'
                        ],
                        excludeFiles: [
                            // macOS
                            '.DS_Store', '.localized', '.AppleDouble', '.LSOverride',

                            // Windows
                            'Thumbs.db', 'desktop.ini',

                            // Python
                            '*.pyc', '*.pyo', '*.pyd', '.Python',

                            // 日志
                            '*.log',

                            // 临时文件
                            '*.tmp', '*.temp', '*.swp', '*.swo', '*~'
                        ],
                        excludePrefixes: [
                            '.', // 隐藏文件
                            '~'  // 备份文件
                        ]
                    };
                }
            }
        }
    </script>
</body>
</html>
